===================
Command-line client
===================

SYNOPSIS
========

:command:`sievemgr` [options_]
[:option:`server`]
[:option:`command`]
[:option:`argument ...`]

:command:`sievemgr` :option:`-h`

:command:`sievemgr` :option:`-V`


DESCRIPTION
===========

:command:`sievemgr` is a command-line client for uploading, downloading,
and managing Sieve scripts using the ManageSieve protocol.

If `command` is given, it is executed on `server`.
Otherwise, commands are read from standard input.
If standard input is a terminal, a shell is entered;
the shell supports tab-completion.

.. only:: html

    `server` defaults to the :confvar:`host` set in :file:`sieverc`
    or, if :confvar:`host` is not set, :file:`localhost`.

.. only:: man

    `server` defaults to the :confvar:`host` set in :manpage:`sieverc(5)`
    or, if :confvar:`host` is not set, :file:`localhost`.


OPERANDS
========

.. option:: server

    URL of the form
    :samp:`[{scheme}://][{login}[:{passwd}]@]{host}[:{port}][/{owner}]`.

    `scheme`
        defaults to "sieve" (and no other scheme is supported).

    `login`
        .. only:: html

            defaults to the :confvar:`login` set for `host` in
            :doc:`sieverc <sieverc>` or :file:`.netrc`, or, if
            no login is set, the current user.

        .. only:: man

            defaults to the :confvar:`login` set for `host` in
            :manpage:`sieverc(5)` or :file:`.netrc`, or,
            if no login is set, the current user.

    `passwd`
        is prompted for by default (see LOGIN_ below for other options).

    `port`
        defaults to 4190 (the standard port for ManageSieve).

    `owner`
        defaults to `login`.

    .. danger::

        Other users can see passwords given on the command line.

.. option:: command

    Command to run (see COMMANDS_ below).

.. option:: argument

    Argument to that command.


OPTIONS
=======

.. option:: -N file

    Use `file` as :file:`.netrc` file.

.. option:: -V

    Show version information.

.. option:: -c file

    Read configuration from `file`.

.. option:: -d

    Enable debugging mode.

.. option:: -f

    Overwrite and remove files without confirmation.

.. option:: -h

    Show a help screen

.. option:: -o key=value

    .. only:: man

        Set configuration `key` to `value`.
        See :manpage:`sieverc(5)` for details.

    .. only:: html

        Set configuration `key` to `value`.
        See :doc:`sieverc` for details.

.. option:: -q

    Be quieter. Give multiple times to decrease output further.

.. option:: -v

    Be more verbose. Give multiple times to increase output further.


COMMANDS
========

.. role:: suboption(strong)
    :class: pre

.. subcommand:: activate script

    Marks `script` as the active script.
    This is the script that the mail server will run for incoming mail.
    Only one script can be active at a time.

.. subcommand:: caps

    .. only:: html

        Show the server's capabilities. Output is serialised as YAML_.

    .. only:: man

        Show the server's capabilities. Output is serialised as YAML.

    .. _YAML: https://www.yaml.org/

.. subcommand:: cat [script ...]

    Print the given scripts to standard output.

.. subcommand:: cd [localdir]

    Change to local working directory to `localdir`.
    `localdir` defaults to the current user's home directory.

.. subcommand:: cert

    .. only:: man
    
        Show the server's TLS certificate. Output is serialised as YAML.

    .. only:: html
        
        Show the server's TLS certificate. Output is serialised as YAML_.

.. subcommand:: cmp script1 script2

    Compare `script1` and `script2`.

.. subcommand:: cp source target

    Download `source` and re-upload it as `target`.

.. subcommand:: deactivate

    Deactivate the active script

.. subcommand:: diff script1 script2

    Show the differences between `script1` and `script2`.

.. subcommand:: ed [-a] script [...]

    Edit `script` with a line editor.

    .. rubric:: Options:

    :suboption:`-a`
        Edit the active script.

.. subcommand:: exit

    Exit the ManageSieve shell. If the command line is empty,
    the shell can also be exited by pressing :kbd:`^D`.

.. subcommand:: get source [target]

    Download `source` and save it as `target`.
    If `target` is omitted, the script is saved under the name of `source`.

.. subcommand:: help, ? [command]

    Show help for `command`.
    If `command` is omitted, list available commands.

    For example:

    .. code:: none

        sieve://user@imap.foo.example> ?ls
        ls [script ...] - list scripts

.. subcommand:: ls [-a] [script ...]

    List the given scripts or, if no `script` is given, all scripts.
    The active script is marked with an asterisk ("\*").

    For example:

    .. code:: none

        sieve://user@imap.foo.example> ls
        foo.sieve* bar.sieve

    .. rubric:: Options:

    :suboption:`-a`
        List the active script only, but do not mark it with an asterisk.

        For example:

        .. code:: none

            sieve://user@imap.foo.example> ls -a
            foo.sieve

.. subcommand:: mget [script ...]

    Download multiple scripts.

.. subcommand:: more [-a] [script ...]

    Display scripts page-by-page.

    .. rubric:: Options:

    :suboption:`-a`
        Display the active script only.

.. subcommand:: mput [script ...]

    Upload multiple scripts.

.. subcommand:: mv source target

    Rename `source` to `target`.

.. subcommand:: put source [target]

    Upload `source` and save it as `target`.
    If `target` is omitted, the script is saved under the name of `source`.

.. subcommand:: python

    Enter a Python read-evaluate-print loop,
    with the current connection as the 'root' object.

    For example:

    .. code:: none

        sieve://user@imap.foo.example> python
        >>> listscripts()
        [('foo.sieve', False), ('bar.sieve', True)]
        >>> noop('foo')
        foo
        >>> exit()
        sieve://user@imap.foo.example>

.. subcommand:: rm [script ...]

    Remove scripts.

.. subcommand:: sh, ! [command] [argument ...]

    Run the system `command` with the given arguments.
    If `command` is omitted, enter a system shell.

    For example:

    .. code:: none

        sieve://user@imap.foo.example> cd sieve
        sieve://user@imap.foo.example> !pwd
        /home/user/sieve
        sieve://user@imap.foo.example> !ls
        foo.sieve bar.sieve
        sieve://user@imap.foo.example> put foo.sieve

    .. code:: none

        sieve://user@imap.foo.example> !
        bash-2.0$

.. subcommand:: su user

    Manage the scripts of `user`.
    Requires elevated privileges.

.. subcommand:: vi [-a] script [...]

    Edit `script` with a visual editor.

    .. rubric:: Options:

    :suboption:`-a`
        Edit the active script only.


PATTERNS
========

If :samp:`*`, :samp:`?`, or :samp:`[{chars}]` occur in *argument*, they
are expanded to local or remote filenames in the same way as a they would
be expanded by a POSIX-compliant shell. If they occur at the place of a
local filename, they are expanded to the matching filenames on the local
machine; if they occur at the place of a remote filename, they are
expanded to the matching filenames on `server`.

For example:

.. code:: none

    sieve://user@imap.foo.example> mput *.sieve

uploads every local file that matches :samp:`*.sieve`.

By contrast,

.. code:: none

    sieve://user@imap.foo.example> rm foo.*

deletes every file that matches :samp:`foo.*` from :file:`imap.foo.example`.

However, be careful with commands that take local *and* remote filenames.
If the first argument matches more than one file, it will 'spill over'
into the second argument. For example:

.. code:: none

    sieve://user@imap.foo.example> put foo* bar*

will upload the first local file that matches :samp:`foo*`, saving
it under the name of the second *local* file that matches :samp:`foo*`.
If :samp:`bar*` matches anything, this will trigger an error, because
:subcommand:`put` only takes two arguments. But if :samp:`bar*` does
*not* match anything, it will expand to an empty list, to the effect
that no error will be triggered.


LOGIN
=====

The login can be automated by reading passwords from the
standard output of a command, by reading them from
:file:`.netrc`, or by using TLS authentication.

Password managers
-----------------

Set :confvar:`getpass` to a :samp:`{command}` to read the password
from the standard output of that *command*.

For example:

.. code:: none

    $ sievemgr -ogetpass='pass $login@$host' user@imap.foo.example

queries :command:`pass` for the password for :file:`user@imap.foo.example`.
:samp:`$login` and :samp:`$host` are expanded to the login for `host`
and `host` respectively.

.. only:: html

    See :doc:`Configuration <sieverc>` for details and more examples.

.. only:: man

    See :manpage:`sieverc(5)` for details and more examples.

The .netrc file
---------------

The :file:`.netrc` file is the traditional facility to automate logins.

For example:

.. code:: none

    machine imap.foo.example
    login user

    machine imap.bar.example
    login user@bar.example
    password secret123


See the GNU network utilities manual (chap. `11.7 <netrc_>`_) for details.

.. warning::

    :file:`.netrc` is unencrypted. Prefer using a password manager.

.. note::

    The default host and the :confvar:`account` and
    :confvar:`macdef` tokens are ignored.

.. _netrc: https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html


TLS authentication
------------------

There are two types of TLS authentication. Sending a certificate may be
required for authentication to be permitted (i.e., sending the certificate
is separate from and insufficient for authentication). Or the user may be
authenticated *by* sending a certificate (sending the certificate is one
way to authenticate, though there may be others, and they may not require
a certificate).

Either way, set :confvar:`cert` to :file:`cert.pem` to load a
client TLS certificate/key pair from :file:`cert.pem`.

To authenticate by sending a certificate,
additionally set :confvar:`authmechs` to ``external``.

.. only:: html

    See :doc:`Configuration <sieverc>` for details.

.. only:: man

    See :manpage:`sieverc(5)` for details.


EXIT STATUS
===========

0
    Success

1
    Failure

2
    Usage error


ENVIRONMENT
===========

.. envvar:: DISPLAY

    X display on which to prompt for a password if standard input is not a TTY.

.. envvar:: EDITOR

    Editor called by :subcommand:`ed` (default: :command:`ed`).

.. envvar:: HOME

    Home directory of the current user.

.. envvar:: LANG

    Controls how passwords and downloaded Sieve scripts are decoded.

.. envvar:: LC_ALL

    Overrides :envvar:`LC_CTYPE`.

.. envvar:: LC_CTYPE

    Overrides :envvar:`LANG`.

.. envvar:: LOGNAME

    Login name of the current user.

.. envvar:: PAGER

    Pager called by :subcommand:`more` (default: :command:`more`).

.. envvar:: NETRC

    Filename of the :file:`.netrc` file
    (default: :file:`{$HOME}/.netrc`).


.. envvar:: VISUAL

    Editor called by :subcommand:`vi` (default: :command:`vi`).

.. envvar:: XDG_CONFIG_HOME

    X Desktop Group base configuration directory
    (default: :file:`{$HOME}/.config`).


FILES
=====

:file:`{$XDG_CONFIG_HOME}/sieve/sieverc`

:file:`{$HOME}/.sieve/sieverc`

:file:`{$HOME}/.sieverc`

:file:`/etc/sieve/sieverc`

:file:`/etc/sieverc`
    The configuration is read from the first file that exists.

    .. only:: man

        See :manpage:`sieverc(5)` for details.

    .. only:: html

        See :doc:`Configuration <sieverc>` for details.

:file:`.netrc`
    Login information.


STANDARDS
=========

* :RFC:`2195` (CRAM-MD5)
* :RFC:`2244` (ACAP)
* :RFC:`4013` (SASLprep)
* :RFC:`4422` (SASL)
* :RFC:`4616` (PLAIN)
* :RFC:`5802` (SCRAM)
* :RFC:`5804` (ManageSieve)
* :RFC:`5019` (Lightweight OCSP)
* :RFC:`6960` (OCSP)
* :RFC:`7677` (SCRAM-SHA-256 and SCRAM-SHA-256-PLUS)


CAVEATS
=======

Credentials are stored in memory. However, page-locking is unfeasible in
Python, so the credentials may be swapped out to the disk.

Checking whether a server's TLS certificate has been revoked requires
the non-standard Python module cryptography_.

.. _cryptography: https://cryptography.io


BUGS
====

:file:`.netrc` records without a :confvar:`password` token wrongly trigger a
parse error in Python up to version 3.9. To avoid valid :file:`.netrc` files
triggering errors, :file:`.netrc` parse errors are turned into warnings
when SieveManager is executed by Python version 3.9 or earlier.


EXAMPLES
========

Upload :file:`script.sieve` to :file:`imap.foo.example` and activate it:

.. code:: none

    $ sievemgr user@imap.foo.example
    sieve://user@imap.foo.example> put script.sieve
    sieve://user@imap.foo.example> activate script.sieve
    sieve://user@imap.foo.example> exit

Reading commands from standard input:

.. code:: none

    $ sievemgr user@imap.foo.example <<EOF
    put script.sieve
    activate script.sieve
    EOF

Download all scripts from :file:`imap.foo.example`:

.. code:: none

    $ sievemgr user@imap.foo.example mget '*'

Edit the active script on :file:`imap.foo.example`:

.. code:: none

    $ sievemgr user@imap.foo.example vi -a


.. only:: man

    SEE ALSO
    ========

    :manpage:`sieverc(5)`
